package com.imachen.ymcc.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.imachen.ymcc.domain.KillActivity;
import com.imachen.ymcc.domain.KillCourse;
import com.imachen.ymcc.enums.GlobalExceptionCode;
import com.imachen.ymcc.exception.GlobalCustomException;
import com.imachen.ymcc.mapper.KillActivityMapper;
import com.imachen.ymcc.service.IKillActivityService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.imachen.ymcc.service.IKillCourseService;
import com.imachen.ymcc.util.AssertUtil;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author imachen
 * @since 2022-10-20
 */
@Service
public class KillActivityServiceImpl extends ServiceImpl<KillActivityMapper, KillActivity> implements IKillActivityService {

    @Autowired
    private IKillCourseService killCourseService;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;


    /**
     * 秒杀活动发布
     * @param activityId
     */
    @Override
    @Transactional
    public void publish(Long activityId) {
        // 1.业务校验
        KillActivity killActivity = selectById(activityId);
        AssertUtil.isNotNull(killActivity, GlobalExceptionCode.KILL_ACTIVITY_IS_NULL_ERROR);
        // 2.判断状态是否为未发布
        Boolean boo = killActivity.getPublishStatus() == KillActivity.WAIT_PUBLISH;
        AssertUtil.isTrue(boo, GlobalExceptionCode.KILL_ACTIVITY_SUCCESS_PUBLISH_ERROR);
        // 3.发布时间必须在活动时间之前,否则无法发布
        Date now = new Date();
        boolean after = killActivity.getStartTime().after(now);
        AssertUtil.isTrue(after,GlobalExceptionCode.KILL_START_ERROR);
        // 4.判断秒杀中是否有课程信息
        List<KillCourse> killCourses = selectCourseByActivityId(activityId);
        if ( killCourses == null || killCourses.size() < 0 ) {
            throw new GlobalCustomException(GlobalExceptionCode.KILL_COURSE_IS_NULL_ERROR);
        }

        // 遍历课程信息
        killCourses.forEach( killCourse -> {
            //设置信号量
            RSemaphore semaphore = redissonClient.getSemaphore(activityId + ":" + killCourse.getId());
            boolean permits = semaphore.trySetPermits(killCourse.getKillCount());
            if ( permits ) {
                // 保存到redis
                redisTemplate.opsForHash().put(
                        "activity:"+ activityId,
                        killCourse.getId().toString(),
                        killCourse
                );
                // 修改秒杀课程状态,发布时间
                killCourse.setPublishStatus(KillActivity.SUCCESS_PUBLISH);
                killCourse.setPublishTime(now);
                killCourseService.updateById(killCourse);
            }
        });
        // 修改秒杀活动状态,发布时间
        killActivity.setPublishStatus(KillActivity.SUCCESS_PUBLISH);
        killActivity.setPublishTime(now);
        updateById(killActivity);
    }

    /**
     * 取消秒杀活动发布
     * @param activityId
     */
    @Override
    public void cancelPublish(Long activityId) {
        // 1.业务校验
        KillActivity killActivity = selectById(activityId);
        AssertUtil.isNotNull(killActivity, GlobalExceptionCode.KILL_ACTIVITY_IS_NULL_ERROR);
        // 2.判断状态是否为发布
        Boolean boo = killActivity.getPublishStatus() == KillActivity.SUCCESS_PUBLISH;
        AssertUtil.isTrue(boo, GlobalExceptionCode.KILL_ACTIVITY_WAIT_PUBLISH_ERROR);

        // 3.判断秒杀中是否有课程信息
        List<KillCourse> killCourses = selectCourseByActivityId(activityId);
        if ( killCourses == null || killCourses.size() < 0 ) {
            throw new GlobalCustomException(GlobalExceptionCode.KILL_COURSE_IS_NULL_ERROR);
        }

        killCourses.forEach( killCourse -> {
            // 删除信号量
            redissonClient.getKeys().delete(activityId + ":" + killCourse.getId());
            // 修改秒杀课程状态,发布时间
            killCourse.setPublishStatus(KillActivity.REMOVE_PUBLISH);
            killCourseService.updateById(killCourse);
        });

        // 删除redis
        redisTemplate.delete("activity:"+ activityId);

        //修改秒杀活动状态
        killActivity.setPublishStatus(KillActivity.REMOVE_PUBLISH);
        updateById(killActivity);

    }


    /**
     * 根据秒杀活动ID查询课程
     * @param activityId
     * @return
     */
    private List<KillCourse> selectCourseByActivityId(Long activityId) {
        return killCourseService.selectList(new EntityWrapper<KillCourse>().eq("activity_id",activityId));
    }
}
